<?php

namespace App\Clients;

use GuzzleHttp\Client;
use GuzzleHttp\Cookie\FileCookieJar;
use GuzzleHttp\Cookie\SetCookie;
use GuzzleHttp\Exception\GuzzleException;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use Illuminate\Support\Facades\Storage;

use Maatwebsite\Excel\Facades\Excel;
use Psr\Http\Message\ResponseInterface;

abstract class Request
{

    public $account = [];
    public $baseUrl = '';
    public $type = '';
    public $reportUrl = '';
    public $cookieDir = 'crm_cookie';

    public $client = null;
    public $jar = null;
    public static $makeCache;

    abstract function login(): bool;

    abstract function isLogin(): bool;

    abstract function loginStatus(): bool;

    public function __construct($account, $url = null, $notAuth = false)
    {
        $this->account = $account;
        if ($url) {
            $this->type = filter_filename($url);
            $this->baseUrl = $url;
        }
        if (!$notAuth)
            if (!$this->loginStatus())
                throw new \Exception("登录失败");

    }

    public function cookieName($name)
    {
        return "{$this->cookieDir}/{$this->type}-{$name}-cookies.json";
    }

    public function cookiePath($name = null): string
    {
        $name = $name ?: $this->account['username'];
        if (!$name)
            throw new \Exception("没有找到对应的用户名");

        return Storage::disk('public')->path($this->cookieName($name));
    }

    public function cookieJarExists($name)
    {
        $name = $name ?: $this->account['username'];
        if (!$name)
            throw new \Exception("没有找到对应的用户名");
        return Storage::disk('public')->exists($this->cookieName($name));
    }

    public function deleteCookieJar($name = null): void
    {
        Storage::disk('public')->delete($this->cookieName($name));
    }

    public function getAccountCookie($name = null)
    {
        if (!$this->jar) {
            $path = $this->cookiePath($name);

            if ($path) {
                $this->jar = new FileCookieJar($path, true);
            } else {
                return false;
            }
        }
        return $this->jar;
    }

    public function putCookieToJar($cookies)
    {
        $jar = $this->getAccountCookie();
        foreach ($cookies as $cookie) {
            $cArr = new SetCookie($cookie);
            $jar->setCookie($cArr);
        }
    }

    public function putCookieToFile($cookie): void
    {
        $jsonString = json_encode($cookie);
        Storage::disk('public')->put($this->cookieName($this->account['username']), $jsonString);
    }

    public function destroyClient(): void
    {

        if ($this->jar) {
            $this->jar->save($this->cookiePath());
        }
        $this->client = null;
    }

    public function createClient($jar = true): Client
    {
        $ip = long2ip(mt_rand());
        $urlArr = parse_url($this->baseUrl);

        // 创建一个重试中间件
        $retryMiddleware = Middleware::retry(function ($retries, $request, $response, $exception) {
            // 重试条件，例如请求超时或服务器错误
            return $retries < 3 && ($response === null || $response->getStatusCode() >= 400);
        }, function ($retries) {

            return 5000; // 返回延迟时间（毫秒）
        });

// 创建一个处理程序堆栈，并将重试中间件添加到其中
        $handlerStack = HandlerStack::create();
        $handlerStack->push($retryMiddleware);


        return new Client([
            'cookies' => $jar,
            'base_uri' => $this->baseUrl,
            'verify' => false,
            'handler' => $handlerStack,
            'http_errors' => false,
            'timeout' => 60,
            'read_timeout' => 60,
            'connect_timeout' => 60,
            'headers' => [
                'Host' => $urlArr['host'],
                'CLIENT-IP' => $ip,
                'X-FORWARDED-FOR' => $ip,
                'Origin' => $this->baseUrl,
                'Referer' => $this->baseUrl,
                'X-Requested-With' => 'XMLHttpRequest',
                'User-Agent' => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36',
            ],
        ]);
    }

    /**
     * 获取 Client
     * @return Client
     */
    public function getClient($name = null): Client
    {
        if (!$this->client) {
            $this->client = $this->createClient($this->getAccountCookie($name));
        }

        return $this->client;
    }

    /**
     * @throws GuzzleException
     */
    public function get($url, $options = []): ResponseInterface
    {
        $client = $this->getClient();
        return $client->get($url, $options);
    }

    /**
     * @throws GuzzleException
     */
    public function post($url, $options): ResponseInterface
    {
        $client = $this->getClient();
        return $client->post($url, $options);
    }

    /**
     * @throws GuzzleException
     */
    public function put($url, $options): ResponseInterface
    {
        $client = $this->getClient();
        return $client->put($url, $options);
    }

    public function postExcel($url, $options,$fileType='xlsx')
    {

        $response = $this->post($url, $options);
        $contents = $response->getBody()->getContents();
        $size = $response->getBody()->getSize();

        if ($size <= 100) {
            $jsonData = json_decode($contents, true);
            if ($jsonData !== null && json_last_error() === JSON_ERROR_NONE) {
                return [null, $jsonData];
            }
        }
        // Check if the contents is valid JSON
        $tempFile = tempnam(sys_get_temp_dir(), $fileType) . ".$fileType";
        file_put_contents($tempFile, $contents);
        $data = Excel::toArray([], $tempFile);
        return [$data, null];
    }

}
